/*******************************************************************************
filename      CString.h
author        Craig Williams

Brief Description:
  Portable version of the std::string class. This was written to get rid of
    of the different versions of std::string, that made them unsafe to use
    across .dll boundries. Namely, a debug and release mode version of
    std::string cannot be used together (the memory layout is different).

  For all intensive purposes, this is the same as std::string with a few
    modifications:
      No iterator support. I don't use them, so I left it out.

      Additional Checking:
        This class handles NULL, which std::string does not.
        A null terminator is append to the end, and it is accessable via
          the index operator and similar.
        No exceptions.

      Added Functions:
        sprintf   - Wrapper around sprintf
        writef    - Wrapper around sprintf
        ToLower   - Converts the string to lower case
        GetLower  - Returns a copy of this string as lower case
        ToUpper   - Converts the string to upper case
        GetUpper  - Returns a copy of this string as upper case
        Hash      - Generates a hash from the string
        GetAsLong - Reads sizeof(long) bytes from the string into a long. Great
                      for sorting.
*******************************************************************************/
#ifndef CSTRING_H
#define CSTRING_H

#include "CVector.h"

class CString
{
  public:
      // Functions defined by C++ Standard.
      //
      // All functions behave like CString, with a few exceptions:
      //   NULL is handled for everything. IE, CString(0) will not crash.
      //   Bounds Checking. All functions that take a pos, or n variable
      //     are varified and corrected. IE,
      //       CString str("foo")
      //       str.insert(123, "bar");
      //     will not generate a out_of_range exception. Instead, pos will
      //     be set to the end of the string (assumed desired behavior).
      //  operator[] & at() can be used to access the NULL terminator.
      //  operator[] & at() will return mGarbage (set to -127) if a invalid
      //    index is specified, instead of generating a out_of_range exception
      //
      // Not Supported:
      //   iterator support
      //   operator<< and operator>>
      //
      // Several Extensions were added. These are listed towards the bottom
      //   of the class. Look for the other comment block.
    CString(void);
    CString(const CString &r);
    CString(const CString &str, unsigned int pos, unsigned int n);
    CString(const char *s, unsigned int n);
    CString(const char *s);
    CString(unsigned int n, char c);

    CString &operator=(const CString &str);
    CString &operator=(const char *s);
    CString &operator=(char c);

    unsigned int size(void) const;
    unsigned int length(void) const;
    unsigned int max_size(void) const;

    void resize(unsigned int n);
    void resize(unsigned int n, char c);

    unsigned int capacity(void) const;
    void reserve(unsigned int res_arg = 0);
    void clear(void);
    bool empty(void) const;

    const char& operator[](unsigned int pos) const;
          char& operator[](unsigned int pos);

    const char& at(unsigned int pos) const;
          char& at(unsigned int pos);

    CString &operator+=(const CString &str);
    CString &operator+=(const char *s);
    CString &operator+=(char c);

    CString &append(const CString &str);
    CString &append(const CString &str, unsigned int pos, unsigned int n);
    CString &append(const char *s, unsigned int n);
    CString &append(const char *s);
    CString &append(unsigned int n, char c);

    void push_back(char c);

    CString &assign(const CString &str);
    CString &assign(const CString &str, unsigned int pos, unsigned int n);
    CString &assign(const char *s, unsigned int n);
    CString &assign(const char *s);
    CString &assign(unsigned int n, char c);

    CString &insert(unsigned int pos1, const CString &str);
    CString &insert(unsigned int pos1, const CString &str, unsigned int pos2, unsigned int n);
    CString &insert(unsigned int pos1, const char *s, unsigned int n);
    CString &insert(unsigned int pos1, const char *s);
    CString &insert(unsigned int pos1, unsigned int n, char c);

    CString &erase(unsigned int pos, unsigned int n);

    CString &replace(unsigned int pos1, unsigned int n1, const CString &str);
    CString &replace(unsigned int pos1, unsigned int n1, const CString &str, unsigned int pos2, unsigned int n2);
    CString &replace(unsigned int pos1, unsigned int n1, const char *s, unsigned int n2);
    CString &replace(unsigned int pos1, unsigned int n1, const char *s);
    CString &replace(unsigned int pos1, unsigned int n1, unsigned int n2, char c);

    unsigned int copy(char *s, unsigned int n, unsigned int pos = 0) const;

    void swap(CString &str);

    const char *c_str(void) const;
    const char *data(void) const;

    unsigned int find(const CString &str, unsigned int pos = 0) const;
    unsigned int find(const char *s, unsigned int pos, unsigned int n) const;
    unsigned int find(const char *s, unsigned int pos = 0) const;
    unsigned int find(char c, unsigned int pos = 0) const;

    unsigned int rfind(const CString &str, unsigned int pos = (unsigned int)~0) const;
    unsigned int rfind(const char *s, unsigned int pos, unsigned int n) const;
    unsigned int rfind(const char *s, unsigned int pos = (unsigned int)~0) const;
    unsigned int rfind(char c, unsigned int pos = (unsigned int)~0) const;

    unsigned int find_first_of(const CString &str, unsigned int pos = 0) const;
    unsigned int find_first_of(const char *s, unsigned int pos, unsigned int n) const;
    unsigned int find_first_of(const char *s, unsigned int pos = 0) const;
    unsigned int find_first_of(char c, unsigned int pos = 0) const;

    unsigned int find_last_of(const CString &str, unsigned int pos = (unsigned int)~0) const;
    unsigned int find_last_of(const char *s, unsigned int pos, unsigned int n) const;
    unsigned int find_last_of(const char *s, unsigned int pos = (unsigned int)~0) const;
    unsigned int find_last_of(char c, unsigned int pos = (unsigned int)~0) const;

    unsigned int find_first_not_of(const CString &str, unsigned int pos = 0) const;
    unsigned int find_first_not_of(const char *s, unsigned int pos, unsigned int n) const;
    unsigned int find_first_not_of(const char *s, unsigned int pos = 0) const;
    unsigned int find_first_not_of(char c, unsigned int pos = 0) const;

    unsigned int find_last_not_of(const CString &str, unsigned int pos = (unsigned int)~0) const;
    unsigned int find_last_not_of(const char *s, unsigned int pos, unsigned int n) const;
    unsigned int find_last_not_of(const char *s, unsigned int pos = (unsigned int)~0) const;
    unsigned int find_last_not_of(char c, unsigned int pos = (unsigned int)~0) const;

    CString substr(unsigned int pos = 0, unsigned int n = (unsigned int)~0) const;

    int compare(const CString &str) const;
    int compare(const char *s) const;
    int compare(unsigned int pos1, unsigned int n1, const CString &str) const;
    int compare(unsigned int pos1, unsigned int n1, const char *s) const;
    int compare(unsigned int pos1, unsigned int n1, const CString &str, unsigned int pos2, unsigned int n2) const;
    int compare(unsigned int pos1, unsigned int n1, const char *s, unsigned int n2) const;

      // Extensions
    void sprintf(const char *fmt, ...); // Max len: 10KB
    void writef (const char *fmt, ...); // same as sprintf
    CString &ToLower(void);
    CString  GetLower(void) const;
    CString &ToUpper(void);
    CString  GetUpper(void) const;

    unsigned long Hash(void);
    unsigned long GetAsLong(void);

  private:
    int  SelfModification(const char *s);
    void ShiftRight(unsigned int start, unsigned int n);

    CVector<char> mStr;
    mutable char  mGarbage; // Returned if [pos] or at(pos) is invalid
};

  // operators defined by the C++ standard
  //   All of these operators behave like CString
bool    operator==(const CString &lhs, const CString &rhs);
bool    operator==(const char    *lhs, const CString &rhs);
bool    operator==(const CString &lhs, const char    *rhs);

bool    operator!=(const CString &lhs, const CString &rhs);
bool    operator!=(const char    *lhs, const CString &rhs);
bool    operator!=(const CString &lhs, const char    *rhs);

bool    operator< (const CString &lhs, const CString &rhs);
bool    operator< (const char    *lhs, const CString &rhs);
bool    operator< (const CString &lhs, const char    *rhs);

bool    operator> (const CString &lhs, const CString &rhs);
bool    operator> (const char    *lhs, const CString &rhs);
bool    operator> (const CString &lhs, const char    *rhs);

bool    operator<=(const CString &lhs, const CString &rhs);
bool    operator<=(const char    *lhs, const CString &rhs);
bool    operator<=(const CString &lhs, const char    *rhs);

bool    operator>=(const CString &lhs, const CString &rhs);
bool    operator>=(const char    *lhs, const CString &rhs);
bool    operator>=(const CString &lhs, const char    *rhs);

CString operator+ (const CString &lhs, const CString &rhs);
CString operator+ (const char    *lhs, const CString &rhs);
CString operator+ (char           lhs, const CString &rhs);
CString operator+ (const CString &lhs, const char    *rhs);
CString operator+ (const CString &lhs, char           rhs);

#endif
